/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "iot_main.h"
#include "ext_dev_if.h"
#include "iot_netcfg.h"
#include "iot_wifi.h"
#include "kv_store.h"
#include "local_net_communication.h"
#include "local_net_dlist.h"
#include "ohos_init.h"
#include <cJSON.h>
#include <string.h>
#include <time.h>

#define SID_KEY "ssid"
#define PWD_KEY "password"
#define GRP_KEY "group"

#define CONFIG_TASK_MAIN_STACKSIZE 0x2000 // main task stacksize must be bigger
#define CONFIG_TASK_MAIN_PRIOR 25         // default task priority
#define CN_MINISECONDS_IN_SECOND 1000
#define LATCH_STATE_OPEN "open"
#define LATCH_STATE_CLOSE "close"
#define APP_RET_SUCCESS 0
#define APP_RET_FAILED -1

typedef enum {
    LATCH_CLOSE = 0,
    LATCH_OPEN
} LatchState;

typedef struct {
    uint8_t localNetInitFlag;
    LatchState currentState;
    LatchState lastState;
} LatchController;

static LatchController g_latchCtl;

static int WifiInfo_get(char *ssid, int id_size, char *pwd, int pd_size, char *group, int group_size)
{
    if (UtilsSetEnv("/data/") != 0) {
        LOG_E("store ssid failed! \n");
        return -1;
    }
    int retval = UtilsGetValue(SID_KEY, ssid, id_size);
    if (retval <= 0) {
        LOG_E("no such ssid stored! \n");
        return -1;
    }

    if (UtilsGetValue(PWD_KEY, pwd, pd_size) < 0) {
        LOG_E("ssid(%s) no password stored! \n", ssid);
        return -1;
    }

    if (UtilsGetValue(GRP_KEY, group, group_size) < 0) {
        LOG_E("ssid(%s) no group stored! \n", group);
        return -1;
    } else {
        LOG_D("ssid : %s, pwd : %s, group : %s! \n", ssid, pwd, group);
    }

    return 0;
}

static void WifiInfo_set(const char *ssid, const char *pwd, const char *group)
{
    if (UtilsSetEnv("/data/") != 0) {
        LOG_E("store ssid failed! \n");
        return;
    }
    if (UtilsSetValue(SID_KEY, ssid) != 0) {
        LOG_E("store ssid failed! \n");
        return;
    }
    if (UtilsSetValue(PWD_KEY, pwd) != 0) {
        LOG_E("store password failed! \n");
        UtilsDeleteValue(SID_KEY);
        return;
    }
    if (UtilsSetValue(GRP_KEY, group) != 0) {
        LOG_E("store group failed! \n");
        UtilsDeleteValue(SID_KEY);
        UtilsDeleteValue(PWD_KEY);
        return;
    }
    LOG_I("store wifi info success! \n");
}

static void WifiDelete(void)
{
    if (UtilsSetEnv("/data/") != 0) {
        LOG_E("store ssid failed! \n");
        return;
    }
    if (UtilsDeleteValue(SID_KEY) != 0) {
        LOG_E("delete ssid failed! \n");
        return;
    }
    if (UtilsDeleteValue(PWD_KEY) != 0) {
        LOG_E("delete password failed! \n");
        return;
    }
    if (UtilsDeleteValue(GRP_KEY) != 0) {
        LOG_E("delete password failed! \n");
        return;
    }
    LOG_I("delete wifi info success! \n");
}

static int8_t msgRecv(const char *msg)
{
    if (!msg) {
        return -1;
    }

    cJSON *unicastJson = cJSON_Parse(msg);
    if (!unicastJson) {
        return -1;
    }
    LOG_I("App recv msg: [%s]", msg);
    cJSON *params = cJSON_GetObjectItem(unicastJson, "params");
    if (!params) {
        LOG_E("params is null!");
        cJSON_Delete(unicastJson);
        return -1;
    }

    cJSON *boolOpenJson = cJSON_GetObjectItem(params, "operate");
    if (boolOpenJson) {
        if (!strcmp("open", boolOpenJson->valuestring)) {
            g_latchCtl.currentState = LATCH_OPEN;
            LOG_I("latch open!");
        } else {
            g_latchCtl.currentState = LATCH_CLOSE;
            LOG_I("latch close!");
        }
    }

    cJSON_Delete(unicastJson);
}

static void LatchControlTask(const void *arg)
{
    LOG_I("LatchControlTask enter.");

    // 初始化按键检测方式
    ExtDevKeyCfgDef extDevKeyCfg[2] = {
        {
            .extDevKeyId = EXT_DEV_KEY_0,
            .extDevKeyWorkType = EXT_DEV_KEY_OBTAIN
        },
        {
            .extDevKeyId = EXT_DEV_KEY_1,
            .extDevKeyWorkType = EXT_DEV_KEY_OBTAIN
        }
    };

    if (EXT_DEV_SUCCESS != ExtDevKeyInit(&extDevKeyCfg, 2)) {
        LOG_E("Failed to init key.");
        return;
    }

    // 初始化指示灯
    if (EXT_DEV_SUCCESS != ExtDevLedInit()) {
        LOG_E("Failed to init led.");
        return;
    }

    // 初始化门闸伺服电机
    if (EXT_DEV_SUCCESS != ExtDevSg90Init()) {
        LOG_E("Init SG90 failed!");
        return;
    }

    while (1) {
        int latchOpenKey = ExtDevKeyIsPress(EXT_DEV_KEY_0);
        int latchCloseKey = ExtDevKeyIsPress(EXT_DEV_KEY_1);
        if ((1 == latchOpenKey) && (0 == latchCloseKey)) {
            g_latchCtl.currentState = LATCH_OPEN;
            LOG_I("LATCH_OPEN");
        } else if ((0 == latchOpenKey) && (1 == latchCloseKey)) {
            g_latchCtl.currentState = LATCH_CLOSE;
            LOG_I("LATCH_CLOSE");
        } else if ((0 != latchOpenKey) && (0 != latchCloseKey)) {
            WifiDelete();
            LOG_I("please press the reset key to config the net!");
        }

        if (g_latchCtl.currentState == g_latchCtl.lastState) {
            usleep(300000);
            continue;
        }
        LOG_I("set latch : %s.", g_latchCtl.currentState ? "open" : "close");
        g_latchCtl.lastState = g_latchCtl.currentState;
        if (LATCH_OPEN == g_latchCtl.currentState) {
            if (EXT_DEV_SUCCESS != ExtDevSetSg90Angle(120)) {
                LOG_E("ExtDevSetSg90Angle failed!");
            }
            ExtDevLedSetSwitch(EXT_DEV_LED_BLUE, EXT_DEV_LED_ON);
        } else if (LATCH_CLOSE == g_latchCtl.currentState) {
            if (EXT_DEV_SUCCESS != ExtDevSetSg90Angle(10)) {
                LOG_E("ExtDevSetSg90Angle failed!");
            }
            ExtDevLedSetSwitch(EXT_DEV_LED_BLUE, EXT_DEV_LED_OFF);
        }

        if (g_latchCtl.localNetInitFlag == 0) {
            usleep(300000);
            LOG_I("localNetInit not ready, just do local things.");
            continue;
        }
        // 发布门禁状态变化通知
        cJSON *latchChangeParamsMsg = cJSON_CreateObject();
        if (latchChangeParamsMsg) {
            cJSON_AddStringToObject(latchChangeParamsMsg, "latchState",
                                    g_latchCtl.currentState ? LATCH_STATE_OPEN : LATCH_STATE_CLOSE);
            char *latchChangeMsg = cJSON_Print(latchChangeParamsMsg);
            LOG_I("latch change msg snd!");
            LocalNetMsgSend("latchChange", latchChangeMsg);
            cJSON_Delete(latchChangeParamsMsg);
            free(latchChangeMsg);
        }
        usleep(300000);
    }

    return;
}

static void IotLocalNetStartTask(const void *arg)
{
    LOG_I("IotLocalNetStartTask entry!");

    g_latchCtl.localNetInitFlag = 0;
    IOT_WifiInfo mWifi = {0};
    DataInfo mData = {"group", {0}};

    // 获取路由信息
    int pressed =
        WifiInfo_get(mWifi.ssid, sizeof(mWifi.ssid), mWifi.psk, sizeof(mWifi.psk), mData.data, sizeof(mData.data));
    if (pressed != 0) {
        // 路由信息获取失败，开始配网
        ExtDevLedSetBlinking(EXT_DEV_LED_RED, 250);
        if (BOARD_NetCfgStartConfigWithData("door_access", &mWifi, &mData) < 0) {
            LOG_E("BOARD_NetCfgStartConfig failed! \n");
            while (1) {
            }
        }
    }

    // 连接网络
    BOARD_ConnectWifi(mWifi.ssid, mWifi.psk);
    // 存储路由信息和group信息
    WifiInfo_set((const char *)mWifi.ssid, (const char *)mWifi.psk, mData.data);
    ExtDevLedSetBlinking(EXT_DEV_LED_RED, 500);
    // 配置设备信息
    NetBroadcastPara_t selfDevInfo;
    memset(&selfDevInfo, 0, sizeof(selfDevInfo));
    memcpy(selfDevInfo.name, "门闸控制器", strlen("门闸控制器"));
    memcpy(selfDevInfo.type, "latch", strlen("latch"));
    memcpy(selfDevInfo.group, mData.data, strlen(mData.data));
    selfDevInfo.priority = 150;
    selfDevInfo.publish = CreateDlist();
    InsertHdlist(selfDevInfo.publish, "latchChange", strlen("latchChange") + 1);
    selfDevInfo.subscribe = CreateDlist();
    InsertHdlist(selfDevInfo.subscribe, "latchControl", strlen("latchControl") + 1);
    if (LocalNetSelfInfoSet(&selfDevInfo)) {
        LOG_E("LocalNetSelfInfoSet failed!");
        return;
    }

    // 注册信息接收回调函数
    LocalNetMsgRecvCbReg(msgRecv);
    // localNet 初始化
    LocalNetInit();

    ExtDevLedSetSwitch(EXT_DEV_LED_RED, EXT_DEV_LED_ON);
    g_latchCtl.localNetInitFlag = 1;

    return;
}

/**
 * @brief IoT Main Entry of the IoT-Flower project
 */
static void IotMainEntry(void)
{
    osThreadAttr_t attr;
    LOG_I("DATE:%s Time:%s \r\n", __DATE__, __TIME__);
    // Create the latch control Main task
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE;
    attr.priority = CONFIG_TASK_MAIN_PRIOR;
    attr.name = "LatchControl";
    (void)osThreadNew((osThreadFunc_t)LatchControlTask, NULL, (const osThreadAttr_t *)&attr);

    // Create the Local Net communication task
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE;
    attr.priority = CONFIG_TASK_MAIN_PRIOR;
    attr.name = "LocalNetStart";
    (void)osThreadNew((osThreadFunc_t)IotLocalNetStartTask, NULL, (const osThreadAttr_t *)&attr);

    return;
}
// Add the IotMainEntry function to the System Startup Procedure
APP_FEATURE_INIT(IotMainEntry);